/*
 * Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
 *
 * Licensed under the Mulan PSL v2.
 * You can use this file according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of the License at
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
 * FOR MORE DETAILS.
 */

#pragma once

#include <atomic>
#include <chrono>
#include <condition_variable>
#include <functional>
#include <list>
#include <map>
#include <memory>
#include <mutex>
#include <set>
#include <string>
#include <thread>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include "DBManager/Common/DBManagerExport.h"
#include "DBManager/Common/DBManagerNamespace.h"

SG_DBMANAGER_NAMESPACE_OPEN

/**
 * @brief 缓存项元数据结构
 */
struct CacheItemMetadata
{
    std::chrono::steady_clock::time_point createTime;      ///< 创建时间
    std::chrono::steady_clock::time_point lastAccessTime;  ///< 最后访问时间
    std::chrono::milliseconds             ttl;             ///< 生存时间（毫秒）
    std::size_t                           memorySize;      ///< 占用内存大小（字节）
    std::function<void (void*)>           destructor;      ///< 销毁函数
    void*                                 dataPtr;         ///< 数据指针
    std::string                           typeName;        ///< 类型名称
};

/**
 * @brief LRU链表节点
 */
struct LRUNode
{
    std::string       key;
    CacheItemMetadata metadata;

    LRUNode (const std::string& k) : key (k)
    {}
};

/**
 * @class CachePool
 * @brief 支持LRU算法和TTL设置的通用缓存池
 *
 * 特性：
 * - 支持LRU（最近最少使用）淘汰策略
 * - 支持TTL（生存时间）自动过期
 * - 线程安全
 * - 自动内存管理和空间计算
 * - 支持多种STL容器类型
 */
class DBManager_DECLSPEC CachePool
{
  public:
    /**
     * @brief 构造函数
     * @param maxMemorySize 最大内存占用大小（字节，默认100MB）
     * @param cleanupIntervalMs 清理过期项的间隔时间（毫秒，默认30秒）
     */
    explicit CachePool (std::size_t               maxMemorySize     = 100 * 1024 * 1024,
                        std::chrono::milliseconds cleanupIntervalMs = std::chrono::milliseconds (10000));

    /**
     * @brief 析构函数
     */
    ~CachePool ();

    /**
     * @brief 添加缓存项
     * @tparam T 数据类型
     * @param key 缓存键
     * @param data 数据指针（缓存池将接管其生命周期）
     * @param ttl 生存时间（毫秒，0表示永不过期）
     * @param destructor 自定义销毁函数（可选）
     * @return 添加成功返回true
     */
    template <typename T>
    bool Put (const std::string&        key,
              T*                        data,
              std::chrono::milliseconds ttl        = std::chrono::milliseconds (60000),
              std::function<void (T*)>  destructor = nullptr);

    /**
     * @brief 更新指定key的缓存项内存大小
     * @param key 缓存键
     * @param newSize 新的内存大小（字节）
     * @return 是否更新成功
     */
    bool UpdateMemorySize (const std::string& key, std::size_t newSize);

    /**
     * @brief 获取缓存项
     * @tparam T 数据类型
     * @param key 缓存键
     * @return 数据指针，如果不存在或已过期返回nullptr
     */
    template <typename T>
    T* Get (const std::string& key);

    /**
     * @brief 获取缓存项（快速版本，跳过过期检查）
     * @tparam T 数据类型
     * @param key 缓存键
     * @return 数据指针，如果不存在返回nullptr
     * @note 此版本假设调用者确定缓存项不会过期，跳过过期检查以提高性能
     */
    template <typename T>
    T* GetFast (const std::string& key);

    /**
     * @brief 检查键是否存在且未过期
     * @param key 缓存键
     * @return 存在且未过期返回true
     */
    bool Contains (const std::string& key);

    /**
     * @brief 移除指定键的缓存项
     * @param key 缓存键
     * @return 移除成功返回true
     */
    bool Remove (const std::string& key);

    /**
     * @brief 清空所有缓存项
     */
    void Clear ();

    /**
     * @brief 手动清理过期项
     * @return 清理的项目数量
     */
    std::size_t CleanupExpired ();

    /**
     * @brief 获取当前缓存项数量
     * @return 缓存项数量
     */
    std::size_t Size () const;

    /**
     * @brief 获取当前内存占用大小
     * @return 内存占用大小（字节）
     */
    std::size_t MemoryUsage () const;

    /**
     * @brief 获取缓存统计信息
     * @return 包含命中率、内存使用等信息的字符串
     */
    std::string GetStatistics () const;

    /**
     * @brief 启动后台清理线程
     */
    void StartCleanupThread ();

    /**
     * @brief 停止后台清理线程
     */
    void StopCleanupThread ();

  private:
    /**
     * @brief 计算STL容器的内存大小
     */
    template <typename T>
    std::size_t CalculateMemorySize (const T* container);

    /**
     * @brief 创建默认销毁函数
     */
    template <typename T>
    std::function<void (void*)> CreateDestructor ();

    /**
     * @brief 移除LRU链表尾部节点
     */
    void RemoveTail ();

    /**
     * @brief 检查项目是否过期
     */
    bool IsExpired (const CacheItemMetadata& metadata) const;

    /**
     * @brief 释放缓存项资源
     */
    void FreeItem (const CacheItemMetadata& metadata);

    /**
     * @brief 确保缓存池容量限制
     */
    void EnforceCapacityLimits ();

    /**
     * @brief 清理过期项（内部版本，假设锁已被持有）
     */
    std::size_t CleanupExpiredInternal ();

    /**
     * @brief 确保缓存池容量限制（内部版本，假设锁已被持有）
     */
    void EnforceCapacityLimitsInternal ();

    /**
     * @brief 后台清理线程函数
     */
    void CleanupThreadFunc ();

  private:
    mutable std::mutex                                            m_mutex;    ///< 互斥锁
    std::unordered_map<std::string, std::list<LRUNode>::iterator> m_cache;    ///< 缓存哈希表
    std::list<LRUNode>                                            m_lruList;  ///< LRU双向链表

    std::size_t m_maxMemorySize;                                              ///< 最大内存占用
    std::size_t m_currentMemorySize;                                          ///< 当前内存占用

    std::chrono::milliseconds    m_cleanupInterval;                           ///< 清理间隔
    std::unique_ptr<std::thread> m_cleanupThread;                             ///< 清理线程
    std::atomic<bool>            m_stopCleanup;                               ///< 停止清理标志
    std::condition_variable      m_cleanupCv;                                 ///< 清理线程条件变量
    std::mutex                   m_cleanupMutex;                              ///< 清理线程条件变量的互斥锁
};

SG_DBMANAGER_NAMESPACE_CLOSE

#include "CachePool.inl"  // 模板实现
